#include "Reader.h"

Reader::Reader() {
	ReaderTimeout = DEFAULT_SERIAL_TIMEOUT;
	
	pthread_mutex_init( &ReaderMtx, NULL );
	pthread_cond_init( &ReaderSgnl, NULL );
}

Reader::~Reader() {
	
	Reset();
	
	pthread_mutex_destroy( &ReaderMtx );
	pthread_cond_destroy( &ReaderSgnl );
}

size_t Reader::OnRequest( vector<BYTE> buffer ) {
	
	size_t rtn = 0;
	if( buffer.size() > 2 )
	{
		size_t command_length = buffer[ 2 ] + 3;
		if( buffer.size() >= command_length )
		{
			MUTEX_LOCK( &ReaderMtx );
			Response.resize( command_length );
			memcpy( &Response[ 0 ], &buffer[ 0 ], command_length );
			rtn = command_length;
			MUTEX_CONDSIGNAL( &ReaderSgnl );
			MUTEX_UNLOCK( &ReaderMtx );
		}
	}
	
	return rtn;
}

bool Reader::Receive( vector<BYTE>& buffer, uint32_t tout ) {
	
	int rtn = 0;
	struct timeval now;
	struct timespec timeout;
	
	MUTEX_LOCK( &ReaderMtx);
	if( Response.size() == 0 ) 
	{
		gettimeofday( &now, NULL );
		timeout.tv_sec = now.tv_sec + tout;
		timeout.tv_nsec = now.tv_usec * 1000;
		
		MUTEX_CONDTWAIT( &ReaderSgnl, &ReaderMtx, &timeout, rtn );
		if( rtn == 0 ) 
		{
			buffer = Response;
			Response.resize( 0 );
		}
	}
	MUTEX_UNLOCK( &ReaderMtx);

	return ( rtn == 0 );
}

BYTE Reader::Checksum( vector<BYTE> frame ) {
	
	BYTE cc = -frame[ 0 ];
	BYTE length = frame[ 2 ];
	
	for( int i = 2 ; i < ( length + 2 ) ; i++ )
		cc -= frame[ i ];
	
	return cc;
}

bool Reader::Check( vector<BYTE> frame, BYTE command ) {
	
	bool rtn = false;
	
	if(( frame[ 0 ] != RESPONSE_FRAME_COMP && frame[ 0 ] != RESPONSE_FRAME ))
	{
		LOG_ERROR("READER\t[%p]\tError de integridad, tipo respuesta 0x%02x.", this, frame[ 0 ] );
		return false;
	}
	
	if(( frame[ 2 ] + 3 ) != frame.size( ))
	{
		LOG_ERROR("READER\t[%p]\tError de integridad, Largos no corresponden %d <> %d.", this, frame[ 2 ] + 3, frame.size());
		return false;
	}
	
	if( Checksum( frame ) != frame[ frame.size() - 1 ] )
	{
		LOG_ERROR("READER\t[%p]\tError de integridad, checksum invalido 0x%02x <> 0x%02x.", this, Checksum( frame ), frame[ frame.size() - 1 ]);
		return false;
	}
	
	if( frame[ 3 ] != command )
	{
		LOG_ERROR("READER\t[%p]\tError de integridad, codigo de respuesta no esperado 0x%02x <> 0x%02x.", this, frame[ 3 ], command );
		return false;
	}
	
	return true;
}

bool Reader::Connect( string device, BYTE br ) {

	if( !Serial::Connect( device, BAUD9600 )) 
	{
		LOG_ERROR("READER\t[%p]\tImposible iniciar puerto serial %s.", this, device.c_str());
		return false;
	}
	
	return true;
}

bool Reader::Init() {

	bool rtn = false;
	vector<BYTE> comreq( 5 ), response;
	
	comreq[ 0 ] = COMMAND_FRAME;
	comreq[ 1 ] = ARBITRARY_STATION;
	comreq[ 2 ] = 0x02;
	comreq[ 3 ] = 0x60;
	comreq[ 4 ] = Checksum( comreq );

	if( Write( comreq ) == comreq.size( ))
	{
		if( Receive( response, ReaderTimeout ))
		{
			rtn = Check( response, 0x60 );
		}
	}
	
	return rtn;
}

bool Reader::SetBaudrate( BYTE br ) {
	
	bool rtn = false;
	vector<BYTE> frame( 6 ), response;
	
	frame[ 0 ] = COMMAND_FRAME;
	frame[ 1 ] = ARBITRARY_STATION;
	frame[ 2 ] = 0x03;
	frame[ 3 ] = SET_BAUD_RATE;
	frame[ 4 ] = br;
	frame[ 5 ] = Checksum( frame );

	if( Write( frame ) == frame.size( ))
	{
		if( Receive( response, ReaderTimeout ))
		{
			rtn = Check( response, SET_BAUD_RATE );
		}
	}
	
	return rtn;
}

bool Reader::GetFirmwareVersion( string& version ) {
	
	bool rtn = false;
	vector<BYTE> frame( 5 ), response;
	
	frame[ 0 ] = COMMAND_FRAME;
	frame[ 1 ] = ARBITRARY_STATION;
	frame[ 2 ] = 0x02;
	frame[ 3 ] = GET_FIRMWARE_VERSION;
	frame[ 4 ] = Checksum( frame );

	if( Write( frame ) == frame.size( ))
	{
		if( Receive( response, ReaderTimeout ))
		{
			if(( rtn = Check( response, GET_FIRMWARE_VERSION )))
			{
				stringstream stream;
				stream << hex << ( int ) response[ 4 ] << "." << hex << ( int ) response[ 5 ];
				version = stream.str();
			}
		}
	}
	
	return rtn;
}

bool Reader::GetTagsNumber( uint8_t& number ) {
	
	bool rtn = false;
	vector<BYTE> frame( 6 ), response;
	
	frame[ 0 ] = COMMAND_FRAME;
	frame[ 1 ] = ARBITRARY_STATION;
	frame[ 2 ] = 0x03;
	frame[ 3 ] = MULTIPLE_IDENTIFY;
	frame[ 4 ] = ISO_18000_6B;
	frame[ 5 ] = Checksum( frame );

	if( Write( frame ) == frame.size( ))
	{
		if( Receive( response, ReaderTimeout ))
		{
			if(( rtn = Check( response, MULTIPLE_IDENTIFY )))
			{
				number = response[ 4 ];
			}
		}
	}
	
	return rtn;
}

PRODUCT_CODE *Reader::GetProductCode( uint8_t& count, PRODUCT_CODE *codes ) {
	
	vector<BYTE> frame( 7 ), response;
	
	frame[ 0 ] = COMMAND_FRAME;
	frame[ 1 ] = ARBITRARY_STATION;
	frame[ 2 ] = 0x04;
	frame[ 3 ] = GET_ID_BUF;
	frame[ 4 ] = 0x01;
	frame[ 5 ] = count;
	frame[ 6 ] = Checksum( frame );

	if( Write( frame ) == frame.size( ))
	{
		if( Receive( response, ReaderTimeout ))
		{
			if( Check( response, GET_ID_BUF ))
			{
				
				codes = new PRODUCT_CODE[ count = response[ 5 ]];
				for( int i = 0 ; i < count ; i++ )
				{
					memcpy(( BYTE * ) &codes[ i ], &response[ 9 + i*10 ], sizeof( PRODUCT_CODE )); 
				}
			}
		}
	}
	
	return codes;	
}
bool Reader::Reset( ) {
	
	bool rtn = false;
	vector<BYTE> frame( 5 ), response;
	
	frame[ 0 ] = COMMAND_FRAME;
	frame[ 1 ] = ARBITRARY_STATION;
	frame[ 2 ] = 0x02;
	frame[ 3 ] = RESET_READER;
	frame[ 4 ] = Checksum( frame );

	if( Write( frame ) == frame.size( ))
	{
		if( Receive( response, ReaderTimeout ))
		{
			rtn = Check( response, RESET_READER );
		}
	}
	
	return rtn;
}

